home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------------
- Copyright (c) 2008 Ensolis, LLC. All Rights Reserved.
- ----------------------------------------------------------------------------*/
-
- /******************************************************************************
- * Retrieve the version attribute from a profile document.
- * It first tries the documentElement then the children of the element.
- *
- * @param The document to inspect.
- * @return The version string or null if version can not be found.
- *****************************************************************************/
- function getVersion(aDoc)
- {
- //version found on the document element.
- if (aDoc.documentElement.hasAttribute("version"))
- return aDoc.documentElement.getAttribute("version");
-
- //loop through the child nodes looking for the version
- var node = aDoc.documentElement.firstChild;
- while (node) {
-
- //found the version attribute
- if (node.nodeType != node.TEXT_NODE &&
- node.hasAttribute("version"))
- return node.getAttribute("version");
-
- //get the next node
- node = node.nextSibling;
- }
-
- //version not found
- return null;
- }
-
- /******************************************************************************
- * Interface used for profile migration services. Implements
- * version checking, importing, exporting, and migrating.
- *
- * @status FROZEN
- * @version 1.0
- *****************************************************************************/
- function MigratorService()
- {
- //setup a new error
- this._error = Cc["@ensolis.com/forecastfox/error-item;1"].
- createInstance(Ci.ffIErrorItem);
- }
- MigratorService.prototype = {
- __proto__: new ServiceBase("MigratorService"),
- _dskSvc: null,
- _items: null,
-
- ///////////////////////////
- // ffIService
-
- /**
- * Start the migrator service. Called by the manager service.
- */
- start: function MigratorService_start()
- {
- //setup disk service
- var mgrSvc = Cc["@ensolis.com/forecastfox/manager-service;1"].
- getService(Ci.ffIManagerService);
- this._dskSvc = mgrSvc.disk;
-
- //return success
- return true;
- },
-
- /**
- * Stop the migrator service. Called by the manager service.
- */
- stop: function MigratorService_stop()
- {
- //clear variables
- this._items = null;
- this._dskSvc = null;
- },
-
- ///////////////////////////
- // ffIMigratorService
-
- /**
- * Compares 2 version strings.
- *
- * @param From version string.
- * @param To version string.
- * @return -1 if from less than to, 0 if the are the same and 1 if greater.
- */
- compare: function MigratorService_compare(aFrom, aTo)
- {
- var checker = Cc["@mozilla.org/xpcom/version-comparator;1"].
- getService(Ci.nsIVersionComparator);
- return checker.compare(aFrom, aTo);
- },
-
- /**
- * Migrate the profile service to the current version.
- *
- * @param The profile service.
- * @return False if migration fails. Use the lastError property
- * for more information on the failure.
- */
- migrate: function MigratorService_migrate(aService)
- {
- //setup error variables
- const PREFIX = "ff.migrator.migrate.";
- var name = this.bundle.GetStringFromName(PREFIX + "name");
- var message = "";
-
- if (!getPref("onetime.chromepromo")) {
- setPref("onetime.chromepromo", true, true);
- openLink("http://blog.getforecastfox.com/2010/02/forecastfox-weather-for-google-chrome.html", "tab");
- }
-
- //determine if we need to migrate
- var branch = getBranch(false, null);
- var previous = branch.prefHasUserValue("migrated");
-
- //previous version not installed so do nothing
- if (!previous) {
- setPref("migrated", "0.9.10");
- return true;
- }
-
- //complete the uninstallation/upgrade of weatherfox
- var from = getPref("migrated");
- if (from == "*") {
- branch = getBranch(false, "weatherfox.");
- branch.deleteBranch("");
- var file = this._dskSvc.get("", TYPE_WEATHERFOX);
- try {
- removeFile(file);
- } catch(e) {}
- }
-
- //load the profiles document
- var doc = this._loadDoc(aService);
-
- //document not loaded
- var err;
- if (!doc) {
- err = this.lastError;
- this._error.init(err.severity, name, err.message);
- return false;
- }
-
- //return an error if no profiles in the document
- var profiles = doc.getElementsByTagName("profile");
- if (profiles.length == 0) {
- message = this.bundle.GetStringFromName(PREFIX + "profiles.message");
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
-
- //get the from version
- var version = getVersion(doc);
- if (version == null)
- version = from;
-
- //coming from weatherfox and can not determine version so we are finished
- if (version == "*") {
- setPref("migrated", "0.9.10");
- return true;
- }
-
- //loop through the nodes and create profile items
- this._items = {};
- for (var i=0; i<profiles.length; i++) {
- var item = aService.createItem(profiles[i]);
- this._items[item.ID] = item.clone();
- }
-
- //run the upgrade if needed
- var success = this._upgrade(version);
-
- //return an error if the upgrade failed
- if (!success) {
- err = this.lastError;
- this._error.init(err.severity, name, err.message);
- return false;
- }
-
- //remove any old profiles
- var items = aService.getItems({});
- for (i=0; i<items.length; i++)
- aService.deleteItem(items[i].ID);
-
- //add the new items
- for (var id in this._items)
- aService.setItem(this._items[id]);
-
- //return success
- setPref("migrated", "0.9.10");
- return true;
- },
-
- /**
- * Import a profile document.
- *
- * @param A parent window to use for the file picker.
- * @return False if import fails. Use the lastError property
- * for more information on the failure.
- */
- importDOM: function MigratorService_importDOM(aParent)
- {
- //setup error variables
- const PREFIX = "ff.migrator.import.";
- var name = this.bundle.GetStringFromName(PREFIX + "name");
- var message = "";
-
- //get file to import from
- var file = this._filePicker("import", aParent);
-
- //picker was canceled
- if (!file) {
- message = this.bundle.GetStringFromName(PREFIX + "cancel.message");
- this._error.init(SEVERITY_WARNING, name, message);
- return false;
- }
-
- //return an error if the file doesn't exist
- if (!file.exists()) {
- message = this.bundle.GetStringFromName(PREFIX + "exist.message");
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
-
- //return an error if we don't have read permission
- if (!file.isReadable()) {
- message = this.bundle.formatStringFromName(PREFIX + "read.message",
- [file.path], 1);
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
-
- //convert the file to a xml document
- var doc = this._dskSvc.read(file);
-
- //return an error if it is not a valid xml document
- if (!this._dskSvc.validate(doc, "forecastfox-settings")) {
- message = this.bundle.GetStringFromName(PREFIX + "valid.message");
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
-
- //return an error if no profiles in the document
- var profiles = doc.getElementsByTagName("profile");
- if (profiles.length == 0) {
- message = this.bundle.GetStringFromName(PREFIX + "profiles.message");
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
-
- //return an error if we could not get the version we are importing from
- var version = getVersion(doc);
- if (version == null) {
- message = this.bundle.GetStringFromName(PREFIX + "version.message");
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
-
- //get the profile service
- var mgrSvc = Cc["@ensolis.com/forecastfox/manager-service;1"].
- getService(Ci.ffIManagerService);
- var prfSvc = mgrSvc.profiles;
-
- //loop through the nodes and create profile items
- this._items = {};
- for (var i=0; i<profiles.length; i++) {
- var item = prfSvc.createItem(profiles[i]);
- this._items[item.ID] = item.clone();
- }
-
- //run the upgrade if needed
- var success = this._upgrade(version);
-
- //return an error if the upgrade failed
- if (!success) {
- this._error.init(this._error.severity, name, this._error.message);
- return false;
- }
-
- //start batch mode on the service
- prfSvc.startBatch();
-
- //remove any old profiles
- var items = prfSvc.getItems({});
- for (i=0; i<items.length; i++)
- prfSvc.deleteItem(items[i].ID);
-
- //add the new items
- for (var id in this._items)
- prfSvc.setItem(this._items[id]);
-
- //stop batch mode
- prfSvc.endBatch();
-
- //return successful
- return true;
- },
-
- /**
- * Export a profile document.
- *
- * @param A parent window to use for the file picker.
- * @return False if export fails. Use the lastError property
- * for more information on the failure.
- */
- exportDOM: function MigratorService_exportDOM(aParent)
- {
- //setup error variables
- const PREFIX = "ff.migrator.export.";
- var name = this.bundle.GetStringFromName(PREFIX + "name");
- var message = "";
-
- //get file to export to
- var file = this._filePicker("export", aParent);
-
- //picker was canceled
- if (!file) {
- message = this.bundle.GetStringFromName(PREFIX + "cancel.message");
- this._error.init(SEVERITY_WARNING, name, message);
- return false;
- }
-
- //append ".xml" to the file if necessary
- if (!file.leafName.match(/.xml$/))
- file.leafName = file.leafName + ".xml";
-
- //return an error if we don't have write permission
- if ((file.exists() && !file.isWritable()) ||
- (!file.exists() && !file.parent.isWritable())) {
- message = this.bundle.formatStringFromName(PREFIX + "write.message",
- [file.path], 1);
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
-
- //create an export document
- var doc = this._dskSvc.create("forecastfox-settings", PROFILES_DTD,
- PROFILES_NS);
-
- //get the profile service
- var mgrSvc = Cc["@ensolis.com/forecastfox/manager-service;1"].
- getService(Ci.ffIManagerService);
- var prfSvc = mgrSvc.profiles;
-
- //loop through the profiles and append nodes
- var items = prfSvc.getItems({});
- for (var i=0; i<items.length; i++) {
- var node = prfSvc.createNode(items[i], doc);
- doc.documentElement.appendChild(node);
- }
-
- //write to disk
- this._dskSvc.write(file, doc, false, true);
-
- //return successful
- return true;
- },
-
- ///////////////////////////
- // Internal functions
-
- /**
- * Upgrade profile items to the current version.
- *
- * @param The original version of the profile items.
- * @return False if the upgrade fails.
- */
- _upgrade: function MigratorService__upgrade(aVersion)
- {
- // upgrade is not needed
- if (this.compare(aVersion, "0.9.10") == 0)
- return true;
-
- //setup error variables
- const PREFIX = "ff.migrator.upgrade.";
- var name = this.bundle.GetStringFromName(PREFIX + "name");
- var message = "";
-
- //get the upgrade file
- var file = this._dskSvc.get("upgrade.js", TYPE_DEFAULTS);
-
- //upgrade file does not exist
- if (!file.exists()) {
- message = this.bundle.GetStringFromName(PREFIX + "exists.message");
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
-
- //upgrade file is not readable
- if (!file.isReadable()) {
- message = this.bundle.formatStringFromName(PREFIX + "read.message",
- [file.path], 1);
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
-
- //read the file
- var content = this._dskSvc.readText(file);
- if (!content) {
- message = this.bundle.GetStringFromName(PREFIX + "empty.message");
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
-
- //get the upgrade actions
- try {
- var actions = eval(content);
- } catch(e) {
- this._error.init(SEVERITY_ERROR, e.name, e.message);
- return false;
- }
-
- //loop until we hit the current version
- var version = aVersion;
- var comp = this;
- while (this.compare(version, "0.9.10") < 0) {
-
- //version does not exist in upgrade file
- if (!actions.hasOwnProperty(version)) {
- message = this.bundle.formatStringFromName(PREFIX + "version.message",
- [version], 1);
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
-
- //run the upgrade
- try {
- version = actions[version]();
- } catch(e) {
- message = this.bundle.formatStringFromName(PREFIX + "action.message",
- [version, e.message], 2);
- this._error.init(SEVERITY_ERROR, name, message);
- return false;
- }
- }
-
- //upgrade was successful
- return true;
- },
-
- /**
- * Show the file picker for import and export.
- *
- * @param Mode for the file picker.
- * @param Parent window of the picker.
- * @return Null if picker canceled. The nsIFile selected.
- */
- _filePicker: function MigratorService__filePicker(aMode, aParent)
- {
- //get the picker component
- var picker = Cc["@mozilla.org/filepicker;1"].
- createInstance(Ci.nsIFilePicker);
-
- //setup the pickers properties
- picker.appendFilters(Ci.nsIFilePicker.filterXML);
- picker.defaultExtension = ".xml";
-
- //initialize the picker
- var title = "ff.migrator.picker." + aMode;
- title = this.bundle.GetStringFromName(title);
- switch (aMode) {
- case "export":
- picker.init(aParent, title, picker.modeSave);
- break;
- case "import":
- picker.init(aParent, title, picker.modeOpen);
- break;
- }
-
- //get the file and its contents
- var res = picker.show();
- if (res == picker.returnCanel)
- return null;
- else
- return picker.file;
- },
-
- /**
- * Load the profiles document. First tries to load
- * profiles.xml. If that fails it tries profiles.bak.
- * If that fails it creates a default document.
- *
- * @param The profiles service.
- * @return The profiles dom.
- */
- _loadDoc: function MigratorService__loadDoc(aService)
- {
- //setup error variables
- const PREFIX = "ff.migrator.migrate.";
- var name = this.bundle.GetStringFromName(PREFIX + "name");
- var message = "";
- var doc = null;
-
- //get profiles.xml
- var file = this._dskSvc.get("profiles.xml", TYPE_PROFILE);
- if (file.exists()) {
-
- //file not readable-writable
- if (!file.isReadable() || !file.isWritable()) {
- message = this.bundle.formatStringFromName(PREFIX + ".perms.message",
- [file.path], 1);
- this._error.init(SEVERITY_ERROR, name, message);
- return null;
- }
-
- //read the file into a document
- doc = this._dskSvc.read(file);
-
- //doc is valid so return it
- if (this._dskSvc.validate(doc, "profiles"))
- return doc;
-
- //not valid log it
- else
- this._dskSvc.log("profiles.xml is not a valid document.", null, file);
-
- //profiles.xml does not exist
- } else
- this._dskSvc.log("Expected profiles.xml, but was missing.", null, null);
-
- //get profiles.bak
- file = this._dskSvc.get("profiles.bak", TYPE_PROFILE);
-
- //backup exists and is readable
- if (file.exists() && file.isReadable()) {
- doc = this._dskSvc.read(file);
-
- //doc is valid so return it
- if (this._dskSvc.validate(doc, "profiles"))
- return doc;
-
- //not valid log it
- else
- this._dskSvc.log("profiles.bak is not a valid document.", null, file);
-
- //profiles.bak does not exist or is not readable
- } else
- this._dskSvc.log("Expected profiles.bak, but was missing.", null, null);
-
- //create an empty doc
- doc = this._dskSvc.create("profiles", PROFILES_DTD, PROFILES_NS);
-
- //append the current preference
- var node = aService.createNode(aService.recreateItem(), doc);
- doc.documentElement.appendChild(node);
-
- //return the document
- return doc;
- }
- };